﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ApplyOrCancelWidget.h"

#include "IUiDocumentViewManager.h"
#include "IMainWindow.h"
#include "IUiView.h"
#include "UpdateCtrlStatusEvent.h"
#include "IActionManager.h"
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QLabel>
#include <QApplication.h>
#include <QMainWindow>
#include "ICommandManager.h"
#include "IAction.h"
#include "CommandParameters.h"
#include "IApplication.h"

#include "GcmpUiDocumentImpl.h"
#include "GnufUIView.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;

// UI样式常量
const static int s_borderWidth                  = 2;
const static int s_borderHeight                 = 2;
const static int s_spaceOfTextAndButtonsArea    = 0;
const static int s_marginBetweenText            = 10;
const static int s_separatorWidth               = 1;
const static int s_buttonAreaWidth              = 52;
const static int s_clientAreaHeight             = 26;
const static int s_hintTextFontPixelSize        = 14;

ApplyOrCancelWidget::ApplyOrCancelWidget(QWidget *parent, int uiDocID)
    // Qt::SubWindow(不能是Qt::Window) 关闭后不会激活视图，并且不然会浮在Ribbon、DocWidget等控件上面
    : QWidget(parent, Qt::FramelessWindowHint | Qt::SubWindow)
    , m_uiDocID(uiDocID)
    , m_isHide(false)
{
    setObjectName("ApplyOrCancelWidget");

    // 根Layout
    m_rootLayout = NEW_AS_QT_CHILD(QHBoxLayout, this);
    m_rootLayout->setSpacing(0);
    m_rootLayout->setContentsMargins(0, 0, 0, 0);
    m_rootLayout->setSizeConstraint(QLayout::SetFixedSize);
    setLayout(m_rootLayout);

    // 背景（绘制内嵌"border"用）
    m_backgroudWidget = NEW_AS_QT_CHILD(QWidget, this);
    m_backgroudWidget->setStyleSheet(".QWidget {background-color: white; border-width: 2px; border-style: solid; border-color: #0066cc;}");
    m_backgroudWidget->setObjectName("backgroundWidget");
    m_rootLayout->addWidget(m_backgroudWidget);

    m_layoutOfBackgroundWidget = NEW_AS_QT_CHILD(QHBoxLayout, m_backgroudWidget);
    m_layoutOfBackgroundWidget->setSpacing(s_spaceOfTextAndButtonsArea);
    m_layoutOfBackgroundWidget->setContentsMargins(s_borderWidth, s_borderHeight, s_borderWidth, s_borderHeight);
    m_backgroudWidget->setLayout(m_layoutOfBackgroundWidget);

    // 左边text区域
    m_layoutOfTextArea = NEW_AS_QT_LAYOUT(QHBoxLayout);
    m_layoutOfTextArea->setSpacing(0);
    m_layoutOfTextArea->setContentsMargins(s_marginBetweenText, 0, s_marginBetweenText, 0);
    m_layoutOfBackgroundWidget->addLayout(m_layoutOfTextArea);

    m_hintTextLabel = NEW_AS_QT_CHILD(QLabel, m_backgroudWidget);
    m_hintTextLabel->setObjectName("hintTabel");
    QFont font;
    font.setBold(true);
    font.setPixelSize(s_hintTextFontPixelSize);
    m_hintTextLabel->setFont(font);
    m_hintTextLabel->setAlignment(Qt::AlignCenter);
    m_hintTextLabel->setFixedHeight(s_clientAreaHeight);
    m_hintTextLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    m_hintTextLabel->setStyleSheet("background-color: white; border: none; color: #0066CD");
    m_layoutOfTextArea->addWidget(m_hintTextLabel);

    // 分割线
    QWidget* separator = NEW_AS_QT_CHILD(QWidget, m_backgroudWidget);
    separator->setFixedHeight(s_clientAreaHeight);
    separator->setFixedWidth(s_separatorWidth);
    separator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    separator->setStyleSheet("border: 1px solid #E3E3E3; \
                              background-color: #E3E3E3;");
    m_layoutOfBackgroundWidget->addWidget(separator);

    // 右边button区域
    m_layoutOfButtonsArea = NEW_AS_QT_LAYOUT(QHBoxLayout);
    m_layoutOfButtonsArea->setSpacing(0);
    m_layoutOfButtonsArea->setContentsMargins(0, 0, 0, 0);
    m_layoutOfBackgroundWidget->addLayout(m_layoutOfButtonsArea);

    m_okButton = NEW_AS_QT_CHILD(QPushButton, m_backgroudWidget);
    m_okButton->setFixedSize(s_buttonAreaWidth / 2, s_clientAreaHeight);
    m_okButton->setIcon(QPixmap(QString::fromStdWString(L":/images/ok.png")));
    m_okButton->setIconSize(QSize(s_buttonAreaWidth / 2, s_clientAreaHeight));
    m_okButton->setToolTip(QString::fromStdWString(GBMP_TR(L"确认")));
    m_okButton->setObjectName("finish");
    QString btnStyle =
        "QPushButton{\
            background-color:white;\
            border:none;\
        }\
        QPushButton:hover{\
            background-color:#E7E7E7;\
        }\
        QPushButton:pressed{\
            background-color:#D7D7D7\
        }";
    m_okButton->setStyleSheet(btnStyle);
    m_okButton->setFocusPolicy(Qt::NoFocus);
    m_layoutOfButtonsArea->addWidget(m_okButton);

    m_cancelButton = NEW_AS_QT_CHILD(QPushButton, m_backgroudWidget);
    m_cancelButton->setFixedSize(s_buttonAreaWidth / 2, s_clientAreaHeight);
    m_cancelButton->setIcon(QPixmap(QString::fromStdWString(L":/images/cancel.png")));
    m_cancelButton->setIconSize(QSize(s_buttonAreaWidth / 2, s_clientAreaHeight));
    m_cancelButton->setToolTip(QString::fromStdWString(GBMP_TR(L"取消")));
    m_cancelButton->setObjectName("cancel");
    m_cancelButton->setStyleSheet(btnStyle);
    m_cancelButton->setFocusPolicy(Qt::NoFocus);
    m_layoutOfButtonsArea->addWidget(m_cancelButton);

    connect(m_okButton,SIGNAL(clicked()),this,SLOT(apply()));
    connect(m_cancelButton,SIGNAL(clicked()),this,SLOT(cancel()));

    installFilter();
    // 初始隐藏
    hide();
}

void ApplyOrCancelWidget::installFilter()
{
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr, L"pUiDocViewMgr is nullptr",L"GDMPLab",L"2024-03-30");
    gcmp::IUiView * pCurUIView = pUiDocViewMgr->GetCurrentUiView();
    if (!pCurUIView)
    {
        return;
    }

    QWidget * pCurViewWidget = QWidget::find(pCurUIView->GetUiViewId());
    if (pCurViewWidget == nullptr)
    {
        return;
    }
    pCurViewWidget->installEventFilter(this);
}

void ApplyOrCancelWidget::apply()
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(!m_hintAndCommands.empty(), L"没有可以应用的命令？",L"GDMPLab",L"2024-03-30");
    // processCommand()没有返回值，无法自主决定是否弹出apply/cancel命令。比如：点击确定之后无法完成apply命令，需要再次点击cancel
    processCommand(m_hintAndCommands.top().ApplyCmd);
}

void ApplyOrCancelWidget::cancel()
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(!m_hintAndCommands.empty(), L"没有可以取消的命令？",L"GDMPLab",L"2024-03-30");
    // processCommand()没有返回值，无法自主决定是否弹出apply/cancel命令。
    processCommand(m_hintAndCommands.top().CancelCmd);
}

void ApplyOrCancelWidget::ResetPosition()
{
    gcmp::IUiView * pCurUIView = IUiDocumentViewManager::Get()->GetCurrentUiView();
    if (!pCurUIView)
    {
        return;
    }

    QWidget * pCurViewWidget = QWidget::find(pCurUIView->GetUiViewId());
    if (!pCurViewWidget || !parentWidget())
    {
        return;
    }

    QWidget * pParentWidget =  parentWidget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParentWidget, L"pParentWidget不应为空",L"GDMPLab",L"2024-03-30");

    QPoint curViewGlobalPosOrigin = pCurViewWidget->mapTo(parentWidget(), QPoint(0, 0));
    if (pCurUIView->IsSubUiView())
    {
        QWidget* pDlgParent = pCurViewWidget->parentWidget();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDlgParent, L"pDlgParent不应为空",L"GDMPLab",L"2024-03-30");
#ifdef _GNUF_WIP_REFACTOR_UIDOC_UIVIEW_LOGIC_
        if (IUiView* pUiView = gcmp::UIView::castTo<IUiView>(pDlgParent))
#else
        if (IUiView* pUiView = dynamic_cast<IUiView*>(pDlgParent))
            
#endif // !_GNUF_WIP_REFACTOR_UIDOC_UIVIEW_LOGIC_
            curViewGlobalPosOrigin = pDlgParent->mapToParent(QPoint(0, 0));
    }

    move(curViewGlobalPosOrigin);
    // 显示到视图的上面
    raise();
}

void ApplyOrCancelWidget::ShowIfThereArePendingCommandPair()
{
    if (m_hintAndCommands.empty())
    {
        return;
    }

    ResetPosition();
    show();
}

void ApplyOrCancelWidget::ForceHide()
{
    hide();
}

void ApplyOrCancelWidget::processCommand(const std::wstring& cmdStr)
{
    gcmp::IUiView* pUIView = IUiDocumentViewManager::Get()->GetCurrentUiView();

    ICommand* pCommand = ICommandManager::Get()->GetCommand(cmdStr);
    gcmp::CommandParameters cmdParams;
    if (pCommand !=nullptr)
    {
        //ActionManager::ProcessCommand(pUIView, pCommand, cmdParams);
        ICommandManager::Get()->SendCommand(cmdStr, cmdParams);
    }
    else
    {
        DBG_WARN(L"无法找到字符串对应的注册命令：" +cmdStr,L"GDMPLab",L"2024-03-30");
        return;
    }

    if (IUiDocumentViewManager::Get()->GetCurrentUiDocument())
    {
        IAction* pCurrentAction = IActionManager::CurrentAction();
        if (pCurrentAction != nullptr)
        {
            if (pUIView != nullptr)
            {
                pUIView->SetCursorPath(pCurrentAction->GetCursorPath());
            }
            else
            {
                DBG_WARN(L"pUiView==nullptr：" + cmdStr,L"GDMPLab",L"2024-03-30");
                return;
            }
        }
        else
        {
            DBG_WARN(L"ctionManager::CurrentAction()==nullptr：" + cmdStr,L"GDMPLab",L"2024-03-30");
            return;
        }
    }

    // 刷新界面。
    gcmp::OwnerPtr<UpdateCtrlStatusEvent> pEvent = NEW_AS_OWNER_PTR(UpdateCtrlStatusEvent);
    IApplication::Get()->PostEvent(TransferOwnership(pEvent));
}

void ApplyOrCancelWidget::keyPressEvent(QKeyEvent *pEvent)
{
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr != nullptr, L"pUiDocViewMgr==nullptr",L"GDMPLab",L"2024-03-30");
    gcmp::IUiView * pCurUIView = pUiDocViewMgr->GetCurrentUiView();
    if (!pCurUIView)
    {
        return;
    }

    QWidget * pCurViewWidget = QWidget::find(pCurUIView->GetUiViewId());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurViewWidget != nullptr,L"widget==nullptr",L"GDMPLab",L"2024-03-30");
    QApplication::sendEvent(pCurViewWidget,(QEvent*)pEvent);
}

bool ApplyOrCancelWidget::eventFilter(QObject *watched, QEvent *event)
{
    if (m_isHide && event->type() == QEvent::MouseMove)
    {
        gcmp::IMainWindow* pUIMainWnd = IMainWindow::GetMainWindow();
        if (pUIMainWnd == nullptr)
        {
            return false;
        }

        gcmp::IUiView * pCurUIView = IUiDocumentViewManager::Get()->GetCurrentUiView();
        if (pCurUIView == nullptr)
        {
            return false;
        }

        QWidget * pCurViewWidget = QWidget::find(pCurUIView->GetUiViewId());
        if (pCurViewWidget == nullptr)
        {
            return false;
        }
        pCurViewWidget->removeEventFilter(this);
        m_isHide = false;
        return true;
    }
    return QWidget::eventFilter(watched, event);
}


bool ApplyOrCancelWidget::PushCommandPair(const std::wstring& hint, const std::wstring& applyCmd, const std::wstring& cancelCmd)
{
    bool isChange = false;
    if (m_hintAndCommands.empty())
    {
        m_hintTextLabel->setText(QString::fromStdWString(hint));
        m_hintAndCommands.push(HintAndCommands(hint, applyCmd, cancelCmd));
        isChange = true;
    }
    else
    {
        // NOTE: 每次在UiDocBase::UpdateView()里都会调用UIManager_Deprecated::SyncUiEditMode()，里面调用新创建出来的顶部编辑模式实例的SetupUi()方法。
        // 需要去除来此同一个编辑模式的不同实例的对FinishCancelDialog UI的重复请求。
        if (hint != m_hintAndCommands.top().Hint)
        {
            m_hintTextLabel->setText(QString::fromStdWString(hint));
            m_hintAndCommands.push(HintAndCommands(hint, applyCmd, cancelCmd));
            isChange = true;
        }
    }
    installFilter();
    ResetPosition();
    show();

    //m_hintTextLabel设置文本之后，需要对窗口的大小进行更新，否则会出现ActionBarDialog的位置计算错误的问题
    adjustSize();
    return isChange;
}

bool ApplyOrCancelWidget::PopCommandPair()
{
    bool isChange = false;
    if (m_hintAndCommands.empty())
    {
        return isChange;
    }

    isChange = true;
    m_hintAndCommands.pop();
    if (m_hintAndCommands.empty())
    {
        m_hintTextLabel->setText(QString());
        m_isHide = true;
        hide();  
    }
    else
    {
        m_hintTextLabel->setText(QString::fromStdWString(m_hintAndCommands.top().Hint));
    }
    return isChange;
}
